/*
 * Copyright (c) 2014. Lorem ipsum dolor sit amet, consectetur adipiscing elit.
 * http://www.apache.org/licenses/LICENSE-2.0
 */

package com.net.MinaEngine.core;


import org.apache.mina.core.buffer.IoBuffer;
import org.apache.mina.core.service.IoHandlerAdapter;
import org.apache.mina.core.session.IdleStatus;
import org.apache.mina.core.session.IoSession;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.concurrent.atomic.AtomicInteger;

/**
 * @author :石头哥哥<br/>
 *         Project:FrameServer1.0
 *         Date: 13-5-19
 *         Time: 下午4:56
 *         this handler is process connected session
 *         the threadPool is :executionHandlerThread,
 *         sessionconfig.addLast("executors",...);
 *         读取数据、发送数据基本
           都在这个接口总完成，这个实例是绑定到IoService 上的，
           有且只有一个实例
 */
public class MServerIoHandler extends IoHandlerAdapter {
    private static final Logger LOGGER = LoggerFactory.getLogger(MServerIoHandler.class);


    /**当前连接session数量*/
    private static final AtomicInteger currentNumOfSession = new AtomicInteger();


    public MServerIoHandler(){
    }

    /**
     * Invoked when a connection has been opened.  This method is invoked after
     * {@link #sessionCreated(IoSession)}.  The biggest difference from
     * {@link #sessionCreated(IoSession)} is that it's invoked from other thread
     * than an I/O processor thread once thread model is configured properly.
     * sessionOpened()方法中，TCP 连接已经真正打开 ，可以在这里执行一些认证操作、发送数据等（MD5 KEY）。
     * executionHandlerThread
     * @param session
     * @throws Exception
     */
    public void sessionOpened(IoSession session) throws Exception {

        currentNumOfSession.incrementAndGet();//add 1
//        if (currentNumOfSession.get()> MServerConfig.maxConnection){
//             //warn   ,take some advances!
//            LOGGER.warn("currentNumOfSession outpace the set value of:"+ MServerConfig.maxConnection);
//        }else {
//            //such as  player add to attribute ，每一个session对应
//            //一个map，通过key获取相应的value
//            session.setAttribute("playerKey",new PlayerInstance(session));
//        }
    }

    /**
     * 1.固化玩家数据
     * 2.回收session资源
     * @param session
     * @throws Exception
     *  Invoked when a connection is closed.
     */
    public void sessionClosed(IoSession session) throws Exception {
//        this.player.save();

        currentNumOfSession.decrementAndGet();//decrement 1
        session.close(true);
    }

    /**
     * session状态callback
     *   <li>READER_IDLE - No data is coming from the remote peer.</li>
     *   <li>WRITER_IDLE- Session is not writing any data.</li>
     *   Invoked with the related {@link IdleStatus} when a connection becomes idle.
     *   在IoSession 的通道进入空闲状态时调用,UDP 不会被调用
     * @param session
     * @param status
     * @throws Exception     here related {related  IdleStatus READER_IDLE}
     */
    public void sessionIdle(IoSession session, IdleStatus status) throws Exception {
        if (status==IdleStatus.READER_IDLE){
            //this session read timeout! ,notify client timeout,
            session.close(true);//
        }
    }

    /**
     *  exceptionCaught handle
     * @param session
     * @param cause
     * @throws Exception
     */
    public void exceptionCaught(IoSession session, Throwable cause){
           session.close(true);
    }
    /**
     * Invoked when a message is received.
     * this method will be called by  logicThread model ;
     * dispatcher message to the logic
     * here dispatcher buf data!
     * executionHandlerThread 线程池分发数据；
     * netty4 和 mina 都是在messageReceived 中分发
     *
     *
     * @param session
     * @param message
     * @throws Exception
     */

   /* public void flush(IoFilter.NextFilter nextFilter, IoSession session) {
        Queue<Object> messageQueue = getMessageQueue();

        while (!messageQueue.isEmpty()) {
            nextFilter.messageReceived(session, messageQueue.poll());
        }
    }*/
    //在mina中，decode message 将添加到messageQueue中，flush(),将会把待处理的数据从队列中
    //poll出，递交到 messageReceived（），业务处理层。
    public void messageReceived(IoSession session, Object message) throws Exception {
        System.out.println("当前线程：>>>>>>"+Thread.currentThread().getName());
//        System.out.println("----->>>>>+++"+session.getConfig().getThroughputCalculationInterval());
        IoBuffer messageBuffer= (IoBuffer) message;
//        byte[]data= (byte[]) message;
//        if (data[0]>0){
//
//        } else {
//
//        }

        //注意释放内存,在业务逻辑处理完毕,发送的数据在netty底层自动release，
        //这里的释放策略在业务数据处理之后 ，如果是json数据解析，那么就应该在
        //parseObject()方法之后
        messageBuffer.free();  //注意释放内存
        //test
        IoBuffer buffer=getWriteBuffer(2,1,null);
        session.write(buffer);


    }

    /**
     * test
     * 构建数据包
     * @param arg1 类型1
     * @param arg2  类型2
     * @param buffer 申请的buf
     * @param paras 待发送的数据
     *              paras数据-----> length+msg+length+msg ... ...
     *              length: byte(1字节),short（2字节）,int（4字节）
     * @return buffer
     */
    private IoBuffer getWriteBuffer(int arg1,int arg2,IoBuffer buffer,Object...paras){
        if (buffer==null){
            buffer= IoBuffer.allocate(0x40).setAutoExpand(true);
        }
        buffer.putShort(Short.MIN_VALUE);//包长占2字节
        buffer.put((byte) arg1);
        if (arg2!=0)buffer.put((byte) arg2);
        for (Object para:paras){
            if (para instanceof Byte){
                buffer.put((Byte) para);  // 占1字节
            }else  if ((para instanceof String)){
                buffer.put(((String) para).getBytes());
            } else if (para instanceof Integer){
                buffer.putInt((Integer) para);    //占4字节
            }else  if (para instanceof Short){
                buffer.putShort((Short) para);  //占2字节
            }
        }
        buffer.putShort(0, (short)(buffer.position()-0x2));
        buffer.flip();
        return buffer;
    }
}
